﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityModManagerNet;
using Harmony12;
using System.Reflection;
using TH20;
using Microsoft.International.Converters.PinYinConverter;
using System.Text.RegularExpressions;
using TH20.ExtContent;
using TH20.UI;
using UnityEngine;

namespace ChineseSearch {
    public static class Main {

        private static UnityModManager.ModEntry _modEntry;

        public static bool Load(UnityModManager.ModEntry modEntry) {
            _modEntry = modEntry;
            modEntry.Logger.Log("Load mod ChineseSearch.");
            HarmonyInstance.Create("ChineseSearch").PatchAll(Assembly.GetExecutingAssembly());
            return true;
        }

        private static List<string> GetPinYinRegex(string text) {
            text = text.Replace(" ", "");
            List<string> result = new List<string>();
            char[] chs;
            foreach (char c in text.ToCharArray()) {
                if (ChineseChar.IsValidChar(c)) {
                    string tmp = "(" + c;
                    HashSet<string> tmpSet = new HashSet<string>();
                    ChineseChar cc = new ChineseChar(c);
                    for (int i = 0; i < cc.PinyinCount; i++) {
                        string py = cc.Pinyins[i].ToLower().TrimEnd(new char[] { '1', '2', '3', '4', '5', '0' });
                        tmpSet.Add(py);
                        tmpSet.Add(py.Substring(0, 1));
                        if (py.Length > 1 && py[1] == 'h')
                            tmpSet.Add(py.Substring(0, 2));
                    }
                    foreach (string s in tmpSet) {
                        tmp += "|" + s;
                    }
                    tmp += ")";
                    result.Add(tmp);
                } else {
                    result.Add(c.ToString());
                }
            }
            return result;
        }

        public static bool MatchPinYin(string prefab, string test) {
            List<string> ls = GetPinYinRegex(prefab);
            string[] vs = ls.ToArray();
            for (int i = 0; i < ls.Count; i++) {
                for (int j = i + 1; j <= ls.Count; j++) {
                    string[] svs = vs.Skip(i).Take(j - i).ToArray();
                    string nt = "^" + string.Join("", svs) + "$";
                    if (Regex.Match(test, nt).Success) {
                        //Console.WriteLine(nt);
                        return true;
                    }
                }
            }
            return false;
        }

        [HarmonyPatch(typeof(RibbonMenuRoomsState), "RoomFilter", new Type[] { typeof(RoomDefinition), typeof(RoomTemplate) })]
        class RibbonMenuRoomsState_RoomFilter_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuRoomsState __instance, ref bool __result, RoomDefinition definition, RoomTemplate template = null) {
                Traverse traverse = Traverse.Create(__instance);
                string filter = traverse.Field("_textFilterTextLive").GetValue<string>().Replace(" ", "");
                if (traverse.Field("_bInputControlTextFilterActive").GetValue<bool>()) {
                    bool result = true;
                    /*if (!traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                        if (traverse.Field("_templatesEnabled").GetValue<bool>() && template != null) {
                            //result = template.UserDefinedName.ToLower().Contains(filter);
                            result = MatchPinYin(template.UserDefinedName.ToLower(), filter);
                        } else {
                            //result = definition.GetLocalisedName().ToLower().Contains(filter, StringComparison.CurrentCulture);
                            result = MatchPinYin(definition.GetLocalisedName().ToLower(), filter);
                        }
                    }*/
                    __result = result; return false;
                }
                if (traverse.Field("_roomFilter").GetValue<RoomFilter>() == null) {
                    __result = true; return false;
                }
                RoomFilter[] filters = definition.Filters;
                if (filters == null) {
                    __result = false; return false;
                }
                for (int i = 0; i < filters.Length; i++) {
                    if (filters[i] == traverse.Field("_roomFilter").GetValue<RoomFilter>()) {
                        __result = true; return false;
                    }
                }
                __result = false; return false;
            }
        }

        [HarmonyPatch(typeof(RibbonMenuRoomsState), "SetRoomsList", new Type[] { })]
        class RibbonMenuRoomsState_SetRoomsList_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuRoomsState __instance) {
                Traverse traverse = Traverse.Create(__instance);
                string filter = traverse.Field("_textFilterTextLive").GetValue<string>().Replace(" ", "");
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().EnableTable();
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowFilter((RectTransform rect) => traverse.Method("FilterRow", rect.GetComponent<RibbonRoomRow>()).GetValue<bool>());
                if (traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                    if (traverse.Field("_roomFilter").GetValue<RoomFilter>() == null) {
                        traverse.Method("SetTemporaryInputControlTextFilterText", string.Empty).GetValue();
                    } else {
                        traverse.Method("SetTemporaryInputControlTextFilterText", traverse.Field("_roomFilter").GetValue<RoomFilter>().LocalisedName.Translation);
                    }
                }
                traverse.Field("_settings").GetValue<RibbonMenuRoomsState.Settings>().FilterButtonAnimator.CurrentState = ButtonAnimator.State.Selectable;
                traverse.Field("_showFilters").SetValue(false);
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowHeight((float)traverse.Field("_settings").GetValue<RibbonMenuRoomsState.Settings>().RowHeight);
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().DestroyAllListItems();
                traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Clear();
                foreach (RoomDefinition roomDefinition in traverse.Field("_level").GetValue<Level>().WorldState.AvailableRooms) {
                    if (!roomDefinition.IsHospitalOrBay) {
                        traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Add(roomDefinition);
                    }
                }
                traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Sort(delegate (RoomDefinition definition1, RoomDefinition definition2) {
                    int itemOrder = traverse.Method("GetItemOrder", traverse.Field("_level").GetValue<Level>().WorldState, traverse.Field("_level").GetValue<Level>().Metagame, definition1).GetValue<int>();
                    int itemOrder2 = traverse.Method("GetItemOrder", traverse.Field("_level").GetValue<Level>().WorldState, traverse.Field("_level").GetValue<Level>().Metagame, definition2).GetValue<int>();
                    return itemOrder.CompareTo(itemOrder2);
                });
                traverse.Field("_rows").GetValue<List<RibbonRoomRow>>().Clear();
                foreach (RoomDefinition room in traverse.Field("_rooms").GetValue<List<RoomDefinition>>()) {
                    if (!traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                        if (!MatchPinYin(room.GetLocalisedName().ToLower(), filter))
                            continue;
                    }
                    traverse.Method("AddRoomRow", room).GetValue();
                }
                return false;
            }
        }

        [HarmonyPatch(typeof(RibbonMenuRoomsState), "SetRoomTemplatesList", new Type[] { })]
        class RibbonMenuRoomsState_SetRoomTemplatesList_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuRoomsState __instance) {
                Traverse traverse = Traverse.Create(__instance);
                string filter = traverse.Field("_textFilterTextLive").GetValue<string>().Replace(" ", "");
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().EnableTable();
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowFilter((RectTransform rect) => traverse.Method("FilterRow", rect.GetComponent<RibbonRoomRow>()).GetValue<bool>());
                if (traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                    if (traverse.Field("_roomFilter").GetValue<RoomFilter>() == null) {
                        traverse.Method("SetTemporaryInputControlTextFilterText", string.Empty).GetValue();
                    } else {
                        traverse.Method("SetTemporaryInputControlTextFilterText", traverse.Field("_roomFilter").GetValue<RoomFilter>().LocalisedName.Translation);
                    }
                }
                traverse.Field("_settings").GetValue<RibbonMenuRoomsState.Settings>().FilterButtonAnimator.CurrentState = ButtonAnimator.State.Selectable;
                traverse.Field("_showFilters").SetValue(false);
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowHeight((float)traverse.Field("_settings").GetValue<RibbonMenuRoomsState.Settings>().RowHeight);
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().DestroyAllListItems();
                traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Clear();
                foreach (RoomDefinition roomDefinition in traverse.Field("_level").GetValue<Level>().WorldState.AvailableRooms) {
                    if (!roomDefinition.IsHospitalOrBay) {
                        traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Add(roomDefinition);
                    }
                }
                traverse.Field("_rooms").GetValue<List<RoomDefinition>>().Sort(delegate (RoomDefinition definition1, RoomDefinition definition2) {
                    int itemOrder = traverse.Method("GetItemOrder", traverse.Field("_level").GetValue<Level>().WorldState, traverse.Field("_level").GetValue<Level>().Metagame, definition1).GetValue<int>();
                    int itemOrder2 = traverse.Method("GetItemOrder", traverse.Field("_level").GetValue<Level>().WorldState, traverse.Field("_level").GetValue<Level>().Metagame, definition2).GetValue<int>();
                    return itemOrder.CompareTo(itemOrder2);
                });
                traverse.Field("_rows").GetValue<List<RibbonRoomRow>>().Clear();
                traverse.Field("_roomTemplates").GetValue<List<RoomTemplate>>().Clear();
                foreach (RoomDefinition room in traverse.Field("_rooms").GetValue<List<RoomDefinition>>()) {
                    foreach (RoomTemplate item in traverse.Field("_level").GetValue<Level>().App.RoomTemplatesManager.GetTemplatesForRoom(room._type)) {
                        if (!traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                            if (!MatchPinYin(item.UserDefinedName.ToLower(), filter))
                                continue;
                        }
                        traverse.Field("_roomTemplates").GetValue<List<RoomTemplate>>().Add(item);
                    }
                }
                foreach (RoomTemplate roomTemplate in traverse.Field("_roomTemplates").GetValue<List<RoomTemplate>>()) {
                    if (roomTemplate != null) {
                        traverse.Method("AddRoomTemplateRow", roomTemplate).GetValue();
                    }
                }
                return false;
            }
        }

        [HarmonyPatch(typeof(RibbonMenuItemsState), "ItemFilter", new Type[] { typeof(IRoomItemDefinition) })]
        class RibbonMenuItemsState_ItemFilter_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuItemsState __instance, ref bool __result, IRoomItemDefinition definition) {
                Traverse traverse = Traverse.Create(__instance);
                string filter = traverse.Field("_textFilterTextLive").GetValue<string>().Replace(" ", "");
                if (traverse.Field("_bInputControlTextFilterActive").GetValue<bool>()) {
                    bool result = true;
                    /*if (!filter.IsNullOrEmpty()) {
                        //result = definition.GetLocalisedName(0).ToLower().Contains(filter, StringComparison.CurrentCulture);
                        result = MatchPinYin(definition.GetLocalisedName(0).ToLower(), filter);
                    }*/
                    __result = result; return false;
                }
                if (traverse.Field("_itemFilter").GetValue<RoomItemFilter>() == null && traverse.Field("_bundleFilter").GetValue<TH20.ExtContent.ExtContentBundleInfo>() == null) {
                    __result = true; return false;
                }
                if (traverse.Field("_itemFilter").GetValue<RoomItemFilter>() == traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().RoomItemFilterDatabase.LockedFilter) {
                    __result = !traverse.Field("_level").GetValue<Level>().Metagame.HasUnlocked(definition); return false;
                }
                if (traverse.Field("_itemFilter").GetValue<RoomItemFilter>() != null) {
                    RoomItemFilter[] filters = definition.Filters;
                    if (filters == null) {
                        __result = false; return false;
                    }
                    for (int i = 0; i < filters.Length; i++) {
                        if (filters[i] == traverse.Field("_itemFilter").GetValue<RoomItemFilter>()) {
                            __result = true; return false;
                        }
                    }
                    __result = false; return false;
                } else {
                    if (traverse.Field("_bundleFilter").GetValue<ExtContentBundleInfo>() == null) {
                        __result = false; return false;
                    }
                    RoomItemDefinitionUGC roomItemDefinitionUGC = definition as RoomItemDefinitionUGC;
                    if (roomItemDefinitionUGC == null) {
                        __result = false; return false;
                    }
                    using (List<TH20.ExtContent.GameItemBase>.Enumerator enumerator = traverse.Field("_bundleFilter").GetValue<TH20.ExtContent.ExtContentBundleInfo>()._bunldeGameItems.GetEnumerator()) {
                        while (enumerator.MoveNext()) {
                            if (enumerator.Current.ContentID == roomItemDefinitionUGC.ContentID) {
                                __result = true; return false;
                            }
                        }
                    }
                    __result = false; return false;
                }
            }
        }
        /*
        [HarmonyPatch(typeof(RibbonMenuItemsState), "FilterRow", new Type[] { typeof(RibbonItemRow) })]
        class RibbonMenuItemsState_FilterRow_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuItemsState __instance,ref bool __result, RibbonItemRow row) {
                Traverse traverse= Traverse.Create(__instance);                
                __result = row == null || traverse.Method("TutorialFilter", row.RoomItemDefinition).GetValue<bool>();
                return false;
            }
        }*/

        [HarmonyPatch(typeof(RibbonMenuItemsState), "SetItemList", new Type[] { typeof(RoomDefinition.Type), typeof(bool) })]
        class RibbonMenuItemsState_SetItemList_Patch {
            [HarmonyPrefix]
            static bool Prefix(RibbonMenuItemsState __instance, RoomDefinition.Type roomType, bool decorationOnly) {
                Traverse traverse = Traverse.Create(__instance);
                MethodInfo GetItemOrder = typeof(TH20.RibbonMenuItemsState).GetMethod("GetItemOrder", BindingFlags.Static | BindingFlags.NonPublic);
                string filter = traverse.Field("_textFilterTextLive").GetValue<string>().Replace(" ", "");
                if (traverse.Field("_textFilterTextLive").GetValue<string>().IsNullOrEmpty()) {
                    if (traverse.Field("_itemFilter").GetValue<RoomItemFilter>() == null && traverse.Field("_bundleFilter").GetValue<ExtContentBundleInfo>() == null) {
                        traverse.Method("SetTemporaryInputControlTextFilterText", string.Empty).GetValue();
                    } else {
                        if (traverse.Field("_itemFilter").GetValue<RoomItemFilter>() != null) {
                            traverse.Method("SetTemporaryInputControlTextFilterText", traverse.Field("_itemFilter").GetValue<RoomItemFilter>().LocalisedName.Translation);
                        }
                        if (traverse.Field("_bundleFilter").GetValue<ExtContentBundleInfo>() != null) {
                            traverse.Method("SetTemporaryInputControlTextFilterText", traverse.Field("_bundleFilter").GetValue<ExtContentBundleInfo>()._bundleName);
                        }
                    }
                }
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableHeadersActive(false);
                if (traverse.Field("_showGridForItems").GetValue<bool>()) {
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().TransitionBody(ref traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().BodyGridAnimatorTarget, traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().BodyGameObjects);
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SwapToggleToTableIcon();
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().EnableGrid();
                } else {
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().TransitionBody(ref traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().BodyTableAnimatorTarget, traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().BodyGameObjects);
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().EnableTable();
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableColumnHeaders(traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().TableHeader);
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableColumnDefinitions(traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().ColumnDefinitions);
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowFilter((RectTransform rect) => traverse.Method("FilterRow", rect.GetComponent<RibbonItemRow>()).GetValue<bool>());
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableRowHeight((float)traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().RowHeight);
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().SetTableDirtyLayout();
                }
                traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().FilterButtonAnimator.CurrentState = ButtonAnimator.State.Selectable;
                traverse.Field("_showFilters").SetValue(false);
                traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().DestroyAllListItems();
                traverse.Field("_activeRoomType").SetValue(roomType);
                traverse.Field("_decorationOnly").SetValue(decorationOnly);
                traverse.Field("_items").GetValue<List<IRoomItemDefinition>>().Clear();
                traverse.Field("_level").GetValue<Level>().WorldState.GetItemsForRoom(roomType, decorationOnly, traverse.Field("_items").GetValue<List<IRoomItemDefinition>>());
                traverse.Field("_items").GetValue<List<IRoomItemDefinition>>().Sort(delegate (IRoomItemDefinition definition1, IRoomItemDefinition definition2) {
                    int itemOrder = (int)GetItemOrder.Invoke(null, new object[] { traverse.Field("_level").GetValue<Level>(), definition1, traverse.Field("RequiredItems").GetValue<RequiredItem[]>() });
                    int itemOrder2 = (int)GetItemOrder.Invoke(null, new object[] { traverse.Field("_level").GetValue<Level>(), definition2, traverse.Field("RequiredItems").GetValue<RequiredItem[]>() });
                    return itemOrder.CompareTo(itemOrder2);
                });
                traverse.Field("_rows").GetValue<List<RibbonItemRow>>().Clear();
                traverse.Field("_requiredRows").GetValue<List<RibbonItemRow>>().Clear();
                foreach (IRoomItemDefinition roomItemDefinition in traverse.Field("_items").GetValue<List<IRoomItemDefinition>>()) {
                    //
                    if (!filter.IsNullOrEmpty()) {
                        if (!MatchPinYin(roomItemDefinition.GetLocalisedName(0).ToLower(), filter))
                            continue;
                    }
                    //
                    GameObject gameObject;
                    if (traverse.Field("_showGridForItems").GetValue<bool>()) {
                        gameObject = traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().InstantiateAsCellInGrid(traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().RibbonItemCellPrefab);
                    } else {
                        gameObject = traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().InstantiateAsRowInTable(traverse.Field("_settings").GetValue<RibbonMenuItemsState.Settings>().RibbonItemRowPrefab);
                    }
                    RibbonItemRow ribbonItemRow = gameObject.GetComponent<RibbonItemRow>();
                    ribbonItemRow.Setup(roomItemDefinition, traverse.Field("_level").GetValue<Level>().Metagame, traverse.Field("_level").GetValue<Level>().GameplayStatsTracker);
                    traverse.Method("RefreshRequiredItemsState", ribbonItemRow).GetValue();
                    ribbonItemRow.Button.onPrimaryDown.AddListener(delegate () {
                        traverse.Method("SelectItem", ribbonItemRow).GetValue();
                    });
                    DynamicButton buttonExtContent = ribbonItemRow.ButtonExtContent;
                    if (buttonExtContent != null) {
                        buttonExtContent.onPrimaryDown.AddListener(delegate () {
                            traverse.Method("OnRowUGCButton", ribbonItemRow).GetValue();
                        });
                    }
                    traverse.Method("RefreshRowMode", ribbonItemRow, false).GetValue();
                    if (ribbonItemRow.CurrentMode == RibbonItemRow.Mode.Locked) {
                        ribbonItemRow.Affordable = traverse.Field("_level").GetValue<Level>().Metagame.CanAffordSilver(ribbonItemRow.RoomItemDefinition);
                    } else {
                        ribbonItemRow.Affordable = (traverse.Field("_level").GetValue<Level>().FinanceManager.Balance >= ribbonItemRow.RoomItemDefinition.GetCost(0));
                    }
                    traverse.Field("_rows").GetValue<List<RibbonItemRow>>().Add(ribbonItemRow);
                    if (traverse.Field("_activeFloorPlan").GetValue<FloorPlan>() != null && traverse.Field("_activeFloorPlan").GetValue<FloorPlan>().Definition.IsRequiredItem(ribbonItemRow.RoomItemDefinition)) {
                        traverse.Field("_requiredRows").GetValue<List<RibbonItemRow>>().Add(ribbonItemRow);
                    }
                }
                if (traverse.Field("_showGridForItems").GetValue<bool>()) {
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().FilterGridCells((RectTransform rect) => traverse.Method("FilterRow", rect.GetComponent<RibbonItemRow>()).GetValue<bool>());
                    int numOfGridColumns = traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().GetNumOfGridColumns();
                    int num = 0;
                    float num2 = traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().GetGridCellWidth() - 0.5f * traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().GetGridCellSpacingHorizontal();
                    foreach (RibbonItemRow ribbonItemRow2 in traverse.Field("_rows").GetValue<List<RibbonItemRow>>()) {
                        if (ribbonItemRow2.isActiveAndEnabled) {
                            int num3 = num % numOfGridColumns;
                            float x = (float)(numOfGridColumns - num3 - 1) * num2;
                            ribbonItemRow2.SetTooltipOffset(new Vector3(x, 0f, 0f));
                            num++;
                        }
                    }
                    traverse.Field("_ribbonMenuView").GetValue<IRibbonMenuView>().RecalulateGridHeight();
                }
                return false;
            }
        }
    }
    /*
    public class Test {
        static void Main(string[] args) {
            string test = "测试abc啊";
            Console.WriteLine(ChineseSearch.Main.MatchPinYin(test, ""));
            Console.WriteLine(ChineseSearch.Main.MatchPinYin(test, "测"));
            Console.WriteLine(ChineseSearch.Main.MatchPinYin(test, "你好"));
            Console.WriteLine(ChineseSearch.Main.MatchPinYin(test, "ces"));
            Console.WriteLine(ChineseSearch.Main.MatchPinYin(test, "csac"));
        }
    }*/
}
